iT邦幫忙

2024 iThome 鐵人賽

DAY 10
0
Python

用 Python 打造你的 Discord BOT系列 第 10

[Day 10] 應用指令的參數限制

  • 分享至 

  • xImage
  •  

今天繼續介紹應用指令的參數,會著重在如何避免使用者輸入不合適的參數。

進度

這應該算是應用指令的最後一篇了...

程式的防呆設計

相信各位程式開發者應該都有這樣的經驗:開發了一個功能,但偏偏使用者並不按照原本設想的方式使用,

因此,開發者往往都需要盡量設想各種可能,並且做出對應的防範措施。而可以讓使用者自行設定參數的斜線指令也是如此,開發者需要防範使用者輸入不合適的參數。

在昨天的文章有提到,如果使用者輸入的型別不正確,就會出現錯誤提示,提醒使用者要輸入正確的格式 (例如:請輸入有效的整數)。但有時候,光是型別還不夠,因此,接下來會介紹更多限制的方法,包含:

  1. 選項
  2. 範圍 (數字)

1. 選項

如果參數的選項不多,直接把所有選項都設定好,並要求使用者只能從中選一個,會是一個很好的選擇。而設定選項的方式也有幾種不同的寫法:

Literal

最簡單的就是使用 Literal,將所有選項列出來。

from typing import Literal

# ...

@client.tree.command(description="點餐")
async def order(
    interaction: discord.Interaction,
    tea: Literal["綠茶", "紅茶", "奶茶"],
    size: Literal["大杯", "中杯", "小杯"],
):
    await interaction.response.send_message(f"點餐結果:{tea}{size}")

# ...

之後設定參數時,就只能從上面所列的選項中進行選擇了。

Enum

除了 Literal,也可以使用 Enum。使用 Enum 除了可以更方便管理這些常數們,也可以做成 key、value 對,讓程式可以依據需求選擇要使用的值。

from enum import Enum

# ...

class Tea(Enum):
    green_tea = "綠茶"
    black_tea = "紅茶"
    milk_tea = "奶茶"

class Size(Enum):
    small = "小杯"
    medium = "中杯"
    large = "大杯"


@client.tree.command(description="點餐")
async def order(
    interaction: discord.Interaction,
    tea: Tea,
    size: Size,
):
    await interaction.response.send_message(f"點餐結果:{tea.value}{size.value}")

# ...

這邊顯示的選項就會是英文,函數內再用 .value 來取得中文。

不過,由於 Enum 本身寫法上的限制,很難反過來改成顯示中文選項,但取得英文的值。想要做到的話,就可以考慮使用下一個方法:choice

choice

直接來看範例。

from discord.app_commands import Choice

# ...

@client.tree.command(description="點餐")
@app_commands.choices(tea=[
    Choice(name='綠茶', value='green_tea'),
    Choice(name='紅茶', value='black_tea'),
    Choice(name='奶茶', value='milk_tea'),
])
@app_commands.choices(size=[
    Choice(name='小杯', value='small'),
    Choice(name='中杯', value='medium'),
    Choice(name='大杯', value='large'),
])
async def order(
    interaction: discord.Interaction,
    tea: Choice[str],
    size: Choice[str],
):
    await interaction.response.send_message(f"點餐結果:{tea.name}{size.name}")

# ...

這個範例還是一樣回傳中文,但如果需要取得英文,改用 .value 取值就好。

2. 範圍

在某些時候,要把所有選項列出來並不容易 (例如:飲料的杯數),但如果選項是在某個範圍內的數字的話,就可以使用 Range

來看一下這個範例:

from discord.app_commands import Range

# ...

@client.tree.command(description="點餐")
async def order(
    interaction: discord.Interaction,
    tea: Literal["綠茶", "紅茶", "奶茶"],
    size: Literal["大杯", "中杯", "小杯"],
    number: Range[int, 1, 10],
):
    await interaction.response.send_message(f"點餐結果:{tea}{size} {number}杯")

# ...

執行後,在輸入數量前,並沒有提示:

但按下 Enter 送出後,就會跳出錯誤提示,要求必須在範圍內才可以。

Range 的用法有幾種不同的變化:

  • Range[int, 10] 表示最小值是 10,沒有上限。
  • Range[int, None, 10] 表示最大值是 10,沒有下限。
  • Range[int, 1, 10] 表示最小值是 1,最大值是 10。
  • Range[float, 1.0, 5.0] 表示最小值是 1.0,最大值是 5.0。
  • Range[str, 1, 10] 表示最小長度是 1,最大長度是 10。

小結

今天算是「暫時」把應用指令收尾了,明天會介紹 bot 指令框架,把目前的觸發條件、應用指令等的寫法重新包裝。

今天是 PyCon 第二天,有幾個跟 FastAPI 相關的演講,感覺格外親切 XD


上一篇
[Day 09] 應用指令的參數與說明
下一篇
[Day 11] 擴充套件 (一):Bot 指令框架
系列文
用 Python 打造你的 Discord BOT31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言